package com.grid.camera.netty;

import com.grid.camera.pelco.PelcoDUtils;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoop;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

@Slf4j
public class NettyClientHandler extends SimpleChannelInboundHandler {

    private final NettyClient nettyClient;

    public NettyClientHandler(NettyClient NettyClient) {
        nettyClient = NettyClient;
    }

    /**
     * 通道连接时调用-处理业务逻辑
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIP = insocket.getAddress().getHostAddress();
        log.info(clientIP + " ：通道已连接！");
    }

    /**
     * 通道闲置触发-启动断线重连功能
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        // 使用过程中断线重连
        final EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(
                () -> {
                    log.error("断线连接中...");
                    nettyClient.connect();
                },
                1,
                TimeUnit.SECONDS);
        ctx.fireChannelInactive();
    }

    /**
     * 长连接读取数据方法-处理业务逻辑
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIP = insocket.getAddress().getHostAddress();

        log.info(clientIP + " Server say : " + msg);

        try {

            byte[] data = null;
            if (msg instanceof String) {
                // 处理字符串消息
                String message = (String) msg;
                log.info("收到服务器消息: {}", message);

                // 将字符串转换为字节数组
                data = message.getBytes();

                // 打印接收到的数据
                log.info("接收到字符串数据: {}", message);

            } else if (msg instanceof ByteBuf) {
                // 处理二进制消息
                ByteBuf buf = (ByteBuf) msg;
                int length = buf.readableBytes();
                data = new byte[length];
                buf.readBytes(data);

                // 打印接收到的数据
                String hexData = PelcoDUtils.bytesToHex(data);
                log.info("接收到二进制数据: {}", hexData);

            } else {
                log.warn("收到未知类型的消息: {}", msg.getClass().getName());
            }

            nettyClient.onReceiveData(clientIP, data);
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
    }

    /**
     * 心跳方法
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state().equals(IdleState.READER_IDLE)) {
                System.out.println("READER_IDLE");
            } else if (event.state().equals(IdleState.WRITER_IDLE)) {
                /** 发送心跳,保持长连接 */
                byte[] buff = {'V', 'Z', 1, 0, 0, 0, 0, 0};
                String cmd = new String(buff);
                ctx.channel().writeAndFlush(cmd);

            } else if (event.state().equals(IdleState.ALL_IDLE)) {
                System.out.println("ALL_IDLE");
            }
        }
        super.userEventTriggered(ctx, evt);
    }

    // 这个方法接收不到数据
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) {}
}
